import python

predicate isVarReference(Stmt stmt) {
    stmt instanceof AssignStmt or
    stmt instanceof AugAssign
}

Expr getSubExprOfAssign(Expr expr)
{
    if expr instanceof Tuple then
        result=expr.(Tuple).getAnElt()
    else if expr instanceof Subscript then
        result=expr.(Subscript).getValue()
    else if expr instanceof Attribute then
        result=expr.(Attribute).getObject()
    else
        result=expr
}

Expr getAllVariable(Stmt stmt,Expr expr)
{
    isVarReference(stmt) and
    expr=stmt.getASubExpression() and
    if stmt instanceof AssignStmt then
        expr=stmt.(AssignStmt).getTarget(0)
    else if stmt instanceof AugAssign then
        expr=stmt.(AugAssign).getTarget()
    else
        expr=expr
    and
    result=getSubExprOfAssign(expr)
}

Stmt getWriteVariableSentence(Stmt stmt)
{
    isVarReference(stmt) and
    result=stmt
}

predicate isParentOfExpr(File f,Module mod,Scope scope,Expr expr) {
    expr.getScope()=scope and
    scope.getEnclosingModule()=mod and
    mod.getFile()=f
}

predicate isParentOfStmt(File f,Module mod,Scope scope,Stmt stmt) {
    stmt.getScope()=scope and
    scope.getEnclosingModule()=mod and
    mod.getFile()=f
}

string getScopeName(Scope scope)
{
    // if exists(scope.getEnclosingModule()) then
    //      result=scope.toString()+","+scope.getEnclosingScope().toString()
    // else
    if scope instanceof Module then
        result=scope.toString()
    else if scope.isTopLevel() then
        result=getScopeName(scope.getEnclosingModule())+","+scope.toString()
    else
        result=getScopeName(scope.getScope())+","+scope.toString()
}

predicate allowIterTypeOfExpr(Expr expr) {
    expr instanceof Attribute or
    expr instanceof Tuple or
    expr instanceof Call or 
    expr instanceof Name or
    expr instanceof Subscript or
    expr instanceof StrConst or
    expr instanceof Num or
    expr instanceof Starred or
    expr instanceof ListComp or
    expr instanceof DictComp or
    expr instanceof BinaryExpr or
    expr instanceof List or
    expr instanceof Dict or
    expr instanceof Slice or
    expr instanceof GeneratorExp or
    expr instanceof IfExp
}

predicate isTerminalExprType(Expr expr) {
    expr instanceof Name or
    expr instanceof Num or
    expr instanceof StrConst
}

string iterVarInExpr(Expr expr)
{ 
    allowIterTypeOfExpr(expr) and
    if expr instanceof Attribute then
        result=iterVarInExpr(expr.(Attribute).getObject())+"."+expr.(Attribute).getName()
    else if expr instanceof Tuple then
        result=iterVarInExpr(expr.(Tuple).getAnElt())
    else if expr instanceof Call then
        result=iterVarInExpr(expr.(Call).getFunc())
        or 
        result= iterVarInExpr(expr.(Call).getAnArg()) 
        or 
        result=iterVarInExpr(expr.(Call).getAKeyword().getValue())
        or
        result=iterVarInExpr(expr.(Call).getKwargs())
    else if expr instanceof Subscript then
        result=iterVarInExpr(expr.(Subscript).getObject())
        +"["+iterVarInExpr(expr.(Subscript).getIndex())+"]"
    else if expr instanceof StrConst then
        result="Strconst"
    else if expr instanceof Num then
        result="Num"
    else if expr instanceof Starred then
        result=iterVarInExpr(expr.(Starred).getValue())
    else if expr instanceof ListComp then
        result=expr.(ListComp).getAnIterationVariable().getId()
        or
        result=iterVarInExpr(expr.(ListComp).getIterable())
        or
        result=iterVarInExpr(expr.(ListComp).getElt())
    else if expr instanceof DictComp then
        result=expr.(DictComp).getAnIterationVariable().getId()
        or
        result=iterVarInExpr(expr.(DictComp).getIterable())
        or
        result=iterVarInExpr(expr.(DictComp).getElt())
    else if expr instanceof BinaryExpr then
        result=iterVarInExpr(expr.(BinaryExpr).getLeft())
        +","+
        iterVarInExpr(expr.(BinaryExpr).getRight())
    else if expr instanceof List then
        result=iterVarInExpr(expr.(List).getAnElt())
    else if expr instanceof Dict then
        result=iterVarInExpr(expr.(Dict).getAKey())
        or
        result=iterVarInExpr(expr.(Dict).getAValue())
    else if expr instanceof Slice then
        if exists(expr.(Slice).getStart()) 
        and exists(expr.(Slice).getStop())
        and exists(expr.(Slice).getStep()) then
            result=iterVarInExpr(expr.(Slice).getStart())+","+iterVarInExpr(expr.(Slice).getStop())
            +","+iterVarInExpr(expr.(Slice).getStep())   
        else if not exists(expr.(Slice).getStep()) then
            result=iterVarInExpr(expr.(Slice).getStart())+","+iterVarInExpr(expr.(Slice).getStop())
        else if not exists(expr.(Slice).getStart()) then
            result=iterVarInExpr(expr.(Slice).getStop())
        else
            result=iterVarInExpr(expr.(Slice).getStart())
    else 
        result=expr.toString()
}


Expr iterExpr(Expr expr)
{
    if expr instanceof Attribute then
        result=iterExpr(expr.(Attribute).getObject())
    else if expr instanceof Call then
        result=iterExpr(expr.getASubExpression())
        or
        result=iterExpr(expr.(Call).getKwargs())
    else if expr instanceof Subscript then
        result=iterExpr(expr.(Subscript).getObject())
    else if expr instanceof GeneratorExp then
        result=iterExpr(expr.(GeneratorExp).getElt())
        or
        result=iterExpr(expr.(GeneratorExp).getIterable())
        or
        result=iterExpr(expr.(GeneratorExp).getAnIterationVariable().getAStore())
    else if
        expr instanceof List
        or
        expr instanceof Slice
        or
        expr instanceof Tuple
        or 
        expr instanceof Dict
    then
        if exists(expr.getASubExpression()) then
            result=iterExpr(expr.getASubExpression())
        else
            result=expr

    else if 
    expr instanceof StrConst 
    or
    expr instanceof Num
    or
    expr instanceof Name
    or
    expr instanceof Lambda
    then
        result=expr
    else
    //     expr instanceof Starred 
    //     or
    //     expr instanceof BinaryExpr 
    //     or
    //     expr instanceof ListComp
    //     or
    //     expr instanceof DictComp
    //     or
    //     expr instanceof BoolExpr
    //     or
    //     expr instanceof Yield
    //     or
    //     expr instanceof Compare
    //     or
    //     expr instanceof GeneratorExp
    //     or
    //     expr instanceof IfExp
    // then
        result=iterExpr(expr.getASubExpression())
}



string expr2string(Expr expr)
{
    if expr instanceof FunctionExpr then
        result=expr.(FunctionExpr).getName()
    else if expr instanceof StrConst then
        result="Strconst"
    else if expr instanceof Num then
        result="Num"
    else if expr instanceof Lambda then
        result="Lambda"
    else
        result=expr.toString()
}

// string expr2string(Expr e)
// {
//     if e instanceof Attribute then
//         result=expr2string(e.(Attribute).getObject())+"."+e.(Attribute).getName()
//     else
//         result=e.toString()
// }

string getLocText(Location e)
{
    result=e.getStartLine()+ ":"+e.getStartColumn()+":"+e.getEndColumn()+":"+e.getEndLine()
}

Stmt iterStmt(Stmt stmt)
{
    if exists(stmt.getASubStatement()) then
        result=stmt
        or
        result=iterStmt(stmt.getASubStatement())
    else
        result=stmt
}

int getLineFirstStmtColumn(Stmt stmt)
{
    result=min(Stmt s,Location l1,Location l2,int h|
        s=iterStmt(stmt.getScope().getAStmt()) and
        l1=s.getLocation() and
        l2=stmt.getLocation() and
        h=l1.getStartColumn() and
        l1.getStartLine()=l2.getStartLine()
        |h)
}

boolean isLeavesNode(AstNode node) {
    if exists(node.getAChildNode()) then
        result=false
    else
        result=true
}

string getNodeType(AstNode node){
    if node instanceof Call then
        result="Call"
    else if node instanceof Function then
        result="Function"
    else if node instanceof Name then
        result="Name"
    else if node instanceof Class then
        result="Class"
    else
        result=node.toString()
}


string getNodeValue(AstNode node){
    if isLeavesNode(node)=true then
        result=node.toString()
    else
        result=""
}

predicate prepare_ast_node_id(AstNode node,string node_type,string node_value,string location) {
    node_type=getNodeType(node)
    and
    node_value=getNodeValue(node)
    and
    location=getLocText(node.getLocation())
}

predicate prepare_cfg_node_id(ControlFlowNode node,string node_type,string node_value,string location) {
    node_type=getNodeType(node.getNode())
    and
    node_value=getNodeValue(node.getNode())
    and
    location=getLocText(node.getLocation())
}

predicate prepare_basicblock_node_id(BasicBlock block,string node_type,string node_value,string filepath,string node_location,string block_location) {
    exists(int b_startline,int b_startcolumn,int b_endline,int b_endcolumn|
        block.hasLocationInfo(filepath, b_startline, b_startcolumn, b_endline, b_endcolumn) 
        and block_location=b_startline+":"+b_startcolumn+":"+b_endcolumn+":"+b_endline)
    and
    prepare_cfg_node_id(block.getLastNode(), node_type, node_value, node_location)
}

predicate isSource(File f) {
    //1=1
    not f.getAbsolutePath().matches("%python%")
}

predicate debug(Location l) {
    1=1
    //l.getStartLine()=21
}